package com.managertrade.controller;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.managertrade.common.Result;
import com.managertrade.config.OkxTraderCache;
import com.managertrade.dao.mysql.entity.UserCopyTrade;
import com.managertrade.dao.mysql.repository.UserCopyTradeRepository;
import com.managertrade.dto.*;
import com.managertrade.dto.base.PageResponseBaseDto;
import com.managertrade.dto.vo.*;
import com.managertrade.dao.mysql.entity.UserFollowTrader;
import com.managertrade.dao.mysql.repository.UserFollowTraderRepository;
import com.managertrade.util.OkxPerpClient;
import com.managertrade.util.OkxProxyHttpClient;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import javax.transaction.Transactional;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.time.Instant;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@RestController
@RequestMapping("/api/okx")
public class CopyTraderController extends BaseController{

    private ObjectMapper objectMapper;
    @Resource
    OkxTraderCache okxTraderCache;


    private static final String OKX_URL = "https://www.okx.com";
    private static final String API_KEY = "d21adddf-ee71-4a48-b215-bec9c2d20d2a";
    private static final String SECRET_KEY = "DEDA389015CA14726EB1AB1382516EB9";
    private static final String URL = "https://www.okx.com/api/v5/copytrading/first-copy-settings";

    private static final String PASSPHRASE = "Tftf5608.";
    @Autowired
    private UserFollowTraderRepository userFollowTraderRepository;

    @Autowired
    private UserCopyTradeRepository userCopyTradeRepository;
    @GetMapping("/copyTraders")
    public Result<PageResponseBaseDto<OkxLeadTraderResponseVO.Trader>> getCopyTraders(@RequestParam Map<String, String> paramMap) throws Exception {

       // 分页参数
        int page = paramMap.get("page") != null ? Integer.parseInt(paramMap.get("page")) : 1;
        int pageSize = paramMap.get("pageSize") != null ? Integer.parseInt(paramMap.get("pageSize")) : 10;

        // 筛选参数
        Integer minLeadDays = paramMap.get("minLeadDays") != null ? Integer.parseInt(paramMap.get("minLeadDays")) : null;
        Integer state = paramMap.get("state") != null ? Integer.parseInt(paramMap.get("state")) : null;
        Double minAssets = !StringUtils.isEmpty(paramMap.get("minAssets")) ? Double.parseDouble(paramMap.get("minAssets")) : null;
        String nickName = !StringUtils.isEmpty(paramMap.get("nickName"))  ? String.valueOf(paramMap.get("nickName")) : null;
        String sortType = !StringUtils.isEmpty(paramMap.get("sortType"))  ? String.valueOf(paramMap.get("sortType")) : null;
        List<OkxLeadTraderResponseVO.Trader> pageNow = okxTraderCache.getPage(page, pageSize,
                nickName,
                convertToDays(minLeadDays),
                state,
                minAssets,sortType);
        int totalCount = okxTraderCache.getTotalCount(nickName, convertToDays(minLeadDays), state, minAssets);
        return Result.success(new PageResponseBaseDto(pageNow,totalCount,page,pageSize));
    }
    /**
     * 将前端传的带单时长类型（1-4）转换成实际天数
     * @param frontValue 前端传的值：1、2、3、4
     * @return 对应天数：7、30、90、180，如果不匹配返回0
     */
    public static int convertToDays(Integer frontValue) {
        if (frontValue == null) return 0;
        switch (frontValue) {
            case 1:
                return 7;
            case 2:
                return 30;
            case 3:
                return 90;
            case 4:
                return 180;
            default:
                return 0; // 不匹配时返回0
        }
    }
    @PostMapping("/firstCopySettings")
    public Result<Object> firstCopySettings(@RequestBody CopySettingsRequestDTO request) throws Exception {
        // 构造时间戳和签名
        String timestamp = Instant.now().toString();
        ObjectMapper objectMapper = new ObjectMapper();
        String requestBody = objectMapper.writeValueAsString(request);
        String preHash = timestamp + "POST" + "/api/v5/copytrading/first-copy-settings" + requestBody;
        String sign = sign(preHash, SECRET_KEY);

        // 构造请求头（转为 JSON 格式请求）
        Map<String, String> headers = new HashMap<>();
        headers.put("OK-ACCESS-KEY", API_KEY);
        headers.put("OK-ACCESS-SIGN", sign);
        headers.put("OK-ACCESS-TIMESTAMP", timestamp);
        headers.put("OK-ACCESS-PASSPHRASE", PASSPHRASE);
        headers.put("Content-Type", "application/json");
        headers.put("Accept", "application/json");
        headers.put("User-Agent", "Mozilla/5.0");

        // 发起 POST 请求（通过本地代理）
        String responseJson = OkxProxyHttpClient.postJson(
                "https://www.okx.com/api/v5/copytrading/first-copy-settings",
                requestBody,
                headers
        );
        log.info("firstCopySettings{}",responseJson);

        // 解析响应 JSON 为 VO
        OkxFirstCopySettingResponseVO responseVO =
                objectMapper.readValue(responseJson, OkxFirstCopySettingResponseVO.class);
        return Result.success(responseVO);
    }

    private static String sign(String preHash, String secretKey) throws Exception {
        Mac mac = Mac.getInstance("HmacSHA256");
        SecretKeySpec secretKeySpec = new SecretKeySpec(secretKey.getBytes(StandardCharsets.UTF_8), "HmacSHA256");
        mac.init(secretKeySpec);
        byte[] hash = mac.doFinal(preHash.getBytes(StandardCharsets.UTF_8));
        return Base64.getEncoder().encodeToString(hash);
    }


    @PostMapping("/postStopCopyTrading")
    public Result<Object> stopCopyTrading(@RequestBody OkxStopCopyTradingRequestDTO dto) throws Exception {
        // OKX API 配置
        String url = "https://www.okx.com/api/v5/copytrading/stop-copy-trading";
        String accessKey = API_KEY;
        String secretKey = SECRET_KEY;
        String passphrase = PASSPHRASE;
        // 时间戳
        String timestamp = String.valueOf(System.currentTimeMillis() / 1000.0);
        // 请求体
        ObjectMapper mapper = new ObjectMapper();
        String bodyJson = mapper.writeValueAsString(dto);
        // 签名
        String method = "POST";
        String path = "/api/v5/copytrading/stop-copy-trading";
        String sign = generateSign(timestamp, method, path, bodyJson, secretKey);
        // 请求头
        Map<String, String> headers = new HashMap<>();
        headers.put("OK-ACCESS-KEY", API_KEY);
        headers.put("OK-ACCESS-SIGN", sign);
        headers.put("OK-ACCESS-TIMESTAMP", timestamp);
        headers.put("OK-ACCESS-PASSPHRASE", PASSPHRASE);
        headers.put("Content-Type", "application/json");
        headers.put("Accept", "application/json");
        headers.put("User-Agent", "Mozilla/5.0");
        ObjectMapper objectMapper = new ObjectMapper();
        String requestBody = objectMapper.writeValueAsString(dto);
        // 请求发送
        String responseJson = OkxProxyHttpClient.postJson(url, requestBody, headers);
        OkxStopCopyTradingResponseVO responseVO =
                objectMapper.readValue(responseJson, OkxStopCopyTradingResponseVO.class);
        log.info("copytrading{}",responseJson);
        return Result.success(responseVO.getData());
    }
    public static String generateSign(String timestamp, String method, String requestPath, String body, String secretKey) throws Exception {
        String preHash = timestamp + method.toUpperCase() + requestPath + (body == null ? "" : body);
        Mac sha256Mac = Mac.getInstance("HmacSHA256");
        SecretKeySpec secretKeySpec = new SecretKeySpec(secretKey.getBytes(), "HmacSHA256");
        sha256Mac.init(secretKeySpec);
        byte[] hash = sha256Mac.doFinal(preHash.getBytes());
        return Base64.getEncoder().encodeToString(hash);
    }

    @PostMapping("/handleWatch")
    @Transactional
    public Result<Object> handleWatch(@RequestBody LeadTraderDTO dto) throws Exception {
        Long userId = getUserId();
        if (!userFollowTraderRepository.existsByUserIdAndLeadTraderId(userId, dto.getUniqueCode())) {
            UserFollowTrader follow = new UserFollowTrader();
            follow.setUserId(userId);
            follow.setLeadTraderId(dto.getUniqueCode());
            follow.setUpdateTime(LocalDateTime.now());
            follow.setPnl(dto.getPnl());
            follow.setNickName(dto.getNickName());
            follow.setPnlRatio(dto.getPnlRatio());
            userFollowTraderRepository.save(follow);
        }else{
            userFollowTraderRepository.deleteByUserIdAndLeadTraderId(userId, dto.getUniqueCode());
        }
        return Result.success();
    }

    @GetMapping ("/getWatchList")
    public Result<PageResponseBaseDto<WatchedTraderVO>> getWatchList(
            @RequestParam(defaultValue = "1") int page,
            @RequestParam(defaultValue = "10") int pageSize,@RequestParam(required = false) String nickName
    ) {
        Long userId = getUserId();
        // 1查询全部关注交易员
        List<UserFollowTrader> followList = userFollowTraderRepository.findByUserId(userId);
        if (followList.isEmpty()) {
            return Result.success(new PageResponseBaseDto<>(Collections.emptyList(), 0, page, pageSize));
        }
        if(!StringUtils.isEmpty(nickName)){
            followList = followList.stream().filter(k->k.getNickName().equals(nickName)).collect(Collectors.toList());
        }
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        // 3 组装 VO
        List<WatchedTraderVO> voList = followList.stream()
                .map(k -> {
                    WatchedTraderVO vo = new WatchedTraderVO(k);
                    vo.setUpdate_lever(k.getUpdateLever());
                    BigDecimal upl = k.getUpdateUpl(); // BigDecimal 类型
                    vo.setUpdate_upl(upl == null ? "0.00000000" : upl.setScale(8, RoundingMode.HALF_UP).toPlainString());
                    vo.setUpdate_side(k.getUpdateSide());
                    vo.setUpdate_instId(k.getUpdateInstId());
                    if(!StringUtils.isEmpty(k.getUpdateOpentime())){
                        vo.setUpdate_opentime(sdf.format(new Date(k.getUpdateOpentime())));
                    }
                    vo.setFollowCount(k.getFollowCount());
                    vo.setTotalPnl(k.getTotalPnl());
                    vo.setWinCount(k.getWinCount());
                    vo.setIsFollowing(k.getIsFollowing());
                    vo.setWinRatio(k.getWinRatio());
                    return vo;
                })
                .collect(Collectors.toList());

        // 4内存排序（按更新时间降序）
        voList.sort((a, b) -> {
            if (a.getUpdate_opentime() == null && b.getUpdate_opentime() == null) return 0;
            if (a.getUpdate_opentime() == null) return 1;
            if (b.getUpdate_opentime() == null) return -1;
            return b.getUpdate_opentime().compareTo(a.getUpdate_opentime());
        });

        // 5手动分页
        int total = voList.size();
        int start = Math.min((page - 1) * pageSize, total);
        int end = Math.min(start + pageSize, total);
        List<WatchedTraderVO> pageList = voList.subList(start, end);

        // 6 返回分页结果
        return Result.success(new PageResponseBaseDto<>(pageList, total, page, pageSize));
    }
    @GetMapping("/subpositions-history")
    public Result<List<CopyTradingSubPositionsHistoryResponse.SubPosition>> getSubPositionsHistory(
            @RequestParam String uniqueCode,
            @RequestParam(required = false, defaultValue = "SWAP") String instType,
            @RequestParam(required = false) String after,
            @RequestParam(required = false) String before,
            @RequestParam(required = false, defaultValue = "100") String limit
    ) throws Exception {
        List<CopyTradingSubPositionsHistoryResponse.SubPosition> traderHistory = OkxPerpClient.getTraderHistory(uniqueCode,"");
        traderHistory.forEach(k->{
            k.setLever(String.valueOf(k.getLeverInt()));
            if("short".equals(k.getPosSide())){
                k.setPosSide("做空");
            }
            if("long".equals(k.getPosSide())){
                k.setPosSide("做多");
            }
        });
        return Result.success(traderHistory);
    }


    @PostMapping("/followTrader")
    public Result<Void> followTrader(@RequestBody FollowTraderRequestVO request) {
        Long userId = getUserId();
        String leadTraderId = request.getLeadTraderId();
        toggleFollow(userId,leadTraderId);
        return Result.success();
    }

    @Transactional
    public void toggleFollow(Long userId, String leadTraderId) {
        UserFollowTrader entity = userFollowTraderRepository
                .findByUserIdAndLeadTraderId(userId, leadTraderId)
                .orElseGet(() -> {
                    UserFollowTrader t = new UserFollowTrader();
                    t.setUserId(userId);
                    t.setLeadTraderId(leadTraderId);
                    t.setIsFollowing(false);
                    t.setFollowCount(0);
                    t.setTotalPnl(BigDecimal.ZERO);
                    t.setWinCount(0);
                    return t;
                });

        boolean newStatus = !entity.getIsFollowing();
        entity.setIsFollowing(newStatus);
        userFollowTraderRepository.save(entity);
    }


    @GetMapping("/follow-history")
    public Result<List<FollowHistoryDTO>> getFollowHistory(
            @RequestParam String uniqueCode,
            @RequestParam(required = false, defaultValue = "SWAP") String instType) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        // instType 这里先保留参数位，后续如果要扩展不同合约类型时用
        List<UserCopyTrade> byUserIdAndLeadTraderIdIn = userCopyTradeRepository.findByUserIdAndTraderId(getUserId(), uniqueCode);
        if(!CollectionUtils.isEmpty(byUserIdAndLeadTraderIdIn)){
            List<FollowHistoryDTO> collect = byUserIdAndLeadTraderIdIn.stream().sorted((a, b) -> b.getOpenTime().compareTo(a.getOpenTime())).map(k -> {
                FollowHistoryDTO followHistoryDTO = new FollowHistoryDTO();
                followHistoryDTO.setSide(k.getPosSide());
                followHistoryDTO.setCloseTime(null);
                followHistoryDTO.setUniqueCode(uniqueCode);
                followHistoryDTO.setPnl(null);
                followHistoryDTO.setInstId(k.getInstId());
                followHistoryDTO.setOpenTime(k.getOpenTime().getTime());
                followHistoryDTO.setLeadTraderOpenTime(k.getLeadTraderOpenTime().getTime());
                return followHistoryDTO;
            }).collect(Collectors.toList());
            return Result.success(collect);
        }
        return Result.success();
    }
}



